class ActionTable {
    constructor(options) {
        this.__globalCounter = 0;
        this.options = options;
        this.id = options.id;
        this.container = options.container;
        this.classes = options.classes;
        this.table_title = options.title;
        this.header = options.header;
        this.onAddition = options.onAddition;
        this.onRemove = options.onRemove;
        this.header.push("Action");
        this.row_num = this.header.length;
        this.data = options.data === undefined ? [] : options.data;
        this.tr_id_mapping = {};
        this.control_items = options.control_items;
        this.header_action_button = options.header_action_button === undefined ? {} : options.header_action_button;
        if (options.header_action_button !== undefined) {
            this.header_action_button_style = this.header_action_button.style === undefined ? {} : this.header_action_button.style;
            this.additionEnabled = this.header_action_button.additionEnabled === undefined ? true : this.header_action_button.additionEnabled;
            this.additionButtonDisabled = this.header_action_button.disabled === undefined ? false : this.header_action_button.disabled;
        } else {
            this.header_action_button_style = {};
            this.additionEnabled = true;
            this.additionButtonDisabled = false;
        }

        this.row_action_button = options.row_action_button === undefined ? {} : options.row_action_button;
        if (options.row_action_button !== undefined) {
            this.row_action_button_style = this.row_action_button.style === undefined ? {} : this.row_action_button.style;
            this.removalEnabled = this.row_action_button.removalEnabled === undefined ? true : this.row_action_button.removalEnabled;
        } else {
            this.row_action_button_style = {};
            this.removalEnabled = true;
        }

        this.selects = {};

        this.__create_table();
    }

    __get_uniq_index() {
        this.__globalCounter++;
        return this.__globalCounter-1;
    }

    add_row(row) {
        if (!this.__data_already_exists(row)) {
            var id = this.__add_row(row);
            this.tr_id_mapping[this.data.length] = id;
            this.data.push(row);
        }
    }

    delete_row(row_id) {
        var tr = document.getElementById(row_id);
        var array = this.__get_array_from_DOM_row(tr);
        var data_index = this.__find_array_index(array, this.data);
        tr.outerHTML = "";
        this.data.splice(data_index, 1);
    }

    delete_row_index(row_pos) {
        var tr = this.get_DOM_row(row_pos);
        var array = this.__get_array_from_DOM_row(tr);
        var data_index = this.__find_array_index(array, this.data);
        tr.outerHTML = "";
        this.data.splice(data_index, 1);
    }

    get_DOM_row(row_pos) {
        var row_id = this.tr_id_mapping[row_pos];
        var tr = document.getElementById(row_id);
        return tr;
    }

    get_data() {
        return this.data;
    }

    clear_table() {
        var dataLength = this.data.length;
        for (var i=0; i<dataLength; i++) {
            this.delete_row_index(i);
        }
    }

    set_table_data(data) {
        this.clear_table();
        for (var i in data) {
            this.add_row(data[i]);
        }
    }

    add_options(id, values) {
        var select = this.selects[id];
        var selected_value = select.value;
        select.innerHTML = ""; // ensure uniqueness
        this.__add_options_to_select(select, values);
        select.value = selected_value;
    }

    __get_array_from_DOM_row(tr) {
        var children = tr.children;
        var array = [];
        for (var i = 0; i < children.length-1; i++) {
            array.push(children[i].innerText);
        }
        return array;
    }

    __data_already_exists(data) {
        return this.__find_array_index(data, this.data) >= 0;
    }

    __find_array_index(value, array) {
        for (var i in array) {
            if (JSON.stringify(array[i]) === JSON.stringify(value)) { // compare array
                return i;
            }
        }
        return -1;
    }

    __create_table() {
        if (this.table_title !== undefined) {
            var label = document.createElement('label');
            label.innerHTML = this.table_title;
            this.container.appendChild(label);
        }
        this.form = document.createElement('form');
        this.table = document.createElement('table');
        this.table.classList.add("table", "table-bordered", "action-table");
        if (this.classes !== undefined) {
            for (var i in this.classes) {
                this.table.classList.add(this.classes[i]);
            }
        }
        this.thead = document.createElement('thead');
        this.tbody = document.createElement('tbody');
        var trHead = document.createElement('tr');
        for (var col of this.header) {
            var th = document.createElement('th');
            th.innerHTML = col;
            trHead.appendChild(th);
        }
        this.thead.appendChild(trHead);

        this.__add_control_row();

        for (var row of this.data) {
            this.__add_row(row);
        }
        this.table.appendChild(this.thead);
        this.table.appendChild(this.tbody);
        this.form.appendChild(this.table);
        this.container.appendChild(this.form);
    }

    __add_row(row) {
        var tr = document.createElement('tr');
        tr.id = "tr_" + this.__uuidv4();
        for (var col of row) {
            var td = document.createElement('td');
            td.textContent = col;
            tr.appendChild(td);
        }
        this.__add_action_button(tr);
        this.tbody.appendChild(tr);
        return tr.id;
    }

    __add_control_row() {
        var tr = document.createElement('tr');
        for (var itemOption of this.control_items) {
            var td = document.createElement('td');
            var item = this.__add_control_item(itemOption);
            if (itemOption.colspan !== undefined) {
                td.colSpan = itemOption.colspan;
            }
            td.appendChild(item);
            tr.appendChild(td);
        }
        var td = document.createElement('td');

        var btn = document.createElement('button');
        var header_action_button_style = this.header_action_button.style === undefined ? {} : this.header_action_button.style;
        if (header_action_button_style.type !== undefined) {
            btn.classList.add("btn", "btn-"+header_action_button_style.type);
        } else {
            btn.classList.add("btn", "btn-primary");
        }
        if (header_action_button_style.tooltip !== undefined) {
            btn.title = header_action_button_style.tooltip;
        }
        if (header_action_button_style.icon !== undefined) {
            btn.innerHTML = '<span class="fa '+header_action_button_style.icon+'"></span>';
        } else {
            btn.innerHTML = '<span class="fa fa-plus-square"></span>';
        }
        btn.type = "button";
        btn.disabled = this.additionButtonDisabled;

        var that = this;
        btn.addEventListener("click", function(evt) {
            var data = [];
            for (var elem of that.form.elements) {
                if (elem.classList.contains('form-group')) {
                    data.push(elem.value);
                }
            }
            if (that.additionEnabled) {
                that.add_row(data);
            }
            if (that.onAddition !== undefined) {
                that.onAddition(data, that);
            }
        });

        td.appendChild(btn);

        tr.appendChild(td);
        this.thead.appendChild(tr);
    }

    __add_control_item(options) {
        var item;
        switch(options.DOMType) {
            case "select":
                item = this.__create_select(options.item_options);
                this.selects[item.id] = item;
                break;
            case "input":
                item = this.__create_input(options.item_options);
                break;
            case "empty":
                item = this.__create_empty(options.item_options);
                break;
            default:
                break;
        }
        return item;
    }

    __add_action_button(tr) {
        var that = this;
        var td = document.createElement('td');
        var btn = document.createElement('button');
        btn.classList.add("btn", "btn-danger");
        btn.innerHTML = '<span class="fa fa-trash"></span>';
        btn.type = "button";
        btn.setAttribute('rowID', tr.id);
        if (that.row_action_button_style.tooltip !== undefined) {
            btn.title = that.row_action_button_style.tooltip;
        }
        if (that.row_action_button_style.style !== undefined) {
            btn.style = that.row_action_button_style.style;
        }
        var that = this;
        btn.addEventListener("click", function(evt) {
            if (that.onRemove !== undefined) {
                var tr = document.getElementById(this.getAttribute('rowID'));
                var data = that.__get_array_from_DOM_row(tr);
                that.onRemove(data, that);
            }
            if (that.removalEnabled) {
                that.delete_row(this.getAttribute('rowID'));
            }
        });
        td.appendChild(btn);

        if (that.row_action_button.others !== undefined) {
            for (var i in that.row_action_button.others) {
                var newBtnOptions = that.row_action_button.others[i];

                var btn_style = newBtnOptions.style !== undefined ? newBtnOptions.style : {};
                var btn = document.createElement('button');
                btn.type = "button";
                if (btn_style.type !== undefined) {
                    btn.classList.add("btn", "btn-"+btn_style.type);
                } else {
                    btn.classList.add("btn", "btn-primary");
                }
                if (btn_style.icon !== undefined) {
                    btn.innerHTML = '<span class="fa '+btn_style.icon+'"></span>';
                } else {
                    btn.innerHTML = '<span class="fa fa-check"></span>';
                }
                if (btn_style.title !== undefined) {
                    btn.title = btn_style.title;
                }
                if (btn_style.style !== undefined) {
                    btn.style = btn_style.style+"margin-left: 3px";
                } else {
                    btn.style = "margin-left: 3px";
                }
                btn.setAttribute('rowID', tr.id);
                if (newBtnOptions.event !== undefined) {
                    btn.addEventListener("click", function(evt) {
                        var tr = document.getElementById(this.getAttribute('rowID'));
                        var data = that.__get_array_from_DOM_row(tr);
                        newBtnOptions.event(data, that);
                    });
                }
                td.appendChild(btn);
            }
        }

        tr.appendChild(td);
    }

    __create_empty(options) {
        var empty = document.createElement('span');
        empty.classList.add("form-group");
        empty.id = options.id !== undefined ? options.id : 'actionTable_controlSelect_'+this.__get_uniq_index();
        return empty;
    }

    __create_input(options) {
        var input = document.createElement('input');
        input.classList.add("form-group");
        input.id = options.id !== undefined ? options.id : 'actionTable_controlSelect_'+this.__get_uniq_index();
        if (options.style !== undefined) {
            input.style = options.style;
        }
        if (options.placeholder !== undefined) {
            input.placeholder = options.placeholder;
        }
        if (options.disabled !== undefined) {
            input.disabled = options.disabled;
        }
        if (options.typeahead !== undefined) {
            var typeaheadOption = options.typeahead;
            $('#'+input.id).typeahead(typeaheadOption);
        }
        return input;
    }

    __create_select(select_options) {
        var select = document.createElement('select');
        select.classList.add("form-group");
        select.id = select_options.id !== undefined ? select_options.id : 'actionTable_controlSelect_'+this.__get_uniq_index();
        select.style.width = "100%";
        this.__add_options_to_select(select, select_options.options);
        if(select_options.default !== undefined) {
            select.value = select_options.default;
        }
        return select;
    }

    __add_options_to_select(select, options) {
        for(var value of options) {
            var option = document.createElement('option');
            if (Array.isArray(value)) { // array of type [value, text]
                option.value = value[1];
                option.textContent = value[1];
            } else { // only value, text=value
                option.value = value;
                option.textContent = value;
            }
            select.appendChild(option);
        }
    }

    __uuidv4() {
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
            return v.toString(16);
        });
    }
}
